package com.uyuni.rpc.client.provider;

import com.uyuni.rpc.client.annotation.RPCService;
import com.uyuni.rpc.client.provider.flow.control.ServiceFlowControllerManager;
import com.uyuni.rpc.client.provider.interceptor.ProviderProxyHandler;
import com.uyuni.rpc.client.provider.model.ServiceWrapper;
import com.uyuni.rpc.common.exception.rpc.RpcWrapperException;
import com.uyuni.rpc.common.protocol.UyuniProtocol;
import com.uyuni.rpc.common.transport.body.PublishServiceCustomBody;
import com.uyuni.rpc.transport.model.RemotingTransporter;
import io.netty.util.internal.StringUtil;
import net.bytebuddy.ByteBuddy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.uyuni.rpc.common.utils.Reflects.*;
import static net.bytebuddy.dynamic.loading.ClassLoadingStrategy.Default.INJECTION;
import static net.bytebuddy.implementation.MethodDelegation.to;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.not;

/**
 * @author BazingaLyn
 * @description 服务提供者端本地服务的编织管理类 将某个方法的某个方法编织成信息发送给registry
 * @time 2016年8月16日
 * @modifytime
 */
public class LocalServerWrapperManager {

    private static final Logger logger = LoggerFactory.getLogger(LocalServerWrapperManager.class);

    private ProviderRegistryController providerController;

    public LocalServerWrapperManager(ProviderRegistryController providerRegistryController) {
        this.providerController = providerRegistryController;
    }

    /**
     * @param port 服务端口号
     * @param obj  暴露的方法的实例
     * @return
     */
    public List<RemotingTransporter> wrapperRegisterInfo(int port, Object... obj) {
        // 声明一个List<RemotingTransporter> 用来保存所有注册请求的实体
        List<RemotingTransporter> remotingTransporters = new ArrayList<>();
        //基本判断，如果暴露的方法是null或者是0，则说明无需编织服务
        if (obj == null) {
            return remotingTransporters;
        }
        Arrays.stream(obj).forEach(o -> {
            //默认的编织对象
            DefaultServiceWrapper defaultServiceWrapper = new DefaultServiceWrapper();
            List<ServiceWrapper> serviceWrappers = defaultServiceWrapper.provider(o).create();
            serviceWrappers.forEach(serviceWrapper -> {
                // new 一个 发布注册服务的消息体
                PublishServiceCustomBody commonCustomBody = new PublishServiceCustomBody();
                commonCustomBody.setConnCount(serviceWrapper.getConnCount());
                commonCustomBody.setDegradeServiceDesc(serviceWrapper.getDegradeServiceDesc());
                commonCustomBody.setDegradeServicePath(serviceWrapper.getDegradeServicePath());
                commonCustomBody.setPort(port);
                commonCustomBody.setServiceProviderName(serviceWrapper.getServiceName());
                commonCustomBody.setVIPService(serviceWrapper.isVIPService());
                commonCustomBody.setWeight(serviceWrapper.getWeight());
                commonCustomBody.setSupportDegradeService(serviceWrapper.isSupportDegradeService());
                commonCustomBody.setFlowController(serviceWrapper.isFlowController());
                commonCustomBody.setMaxCallCountInMinute(serviceWrapper.getMaxCallCountInMinute());
                //创建一个远程请求传输的对象
                RemotingTransporter remotingTransporter = RemotingTransporter.createRequestTransporter(UyuniProtocol.PUBLISH_SERVICE, commonCustomBody);
                remotingTransporters.add(remotingTransporter);
            });
        });
        return remotingTransporters;

    }

    /**
     * @author BazingaLyn
     * @description 方法编织服务
     * @time 2016年8月16日
     * @modifytime
     */
    class DefaultServiceWrapper implements ServiceWrapperWorker {

        //全局拦截proxy
        private volatile ProviderProxyHandler globalProviderProxyHandler;

        //某个方法实例编织后的对象
        private Object serviceProvider;
        //该方法降级时所对应的mock对象实例(最好是两个同样的接口)
        private Object mockDegradeServiceProvider;

        @Override
        public ServiceWrapperWorker provider(Object serviceProvider) {
            //如果proxy的对象是null,实例对象无需编织，直接返回
            if (null == globalProviderProxyHandler) {
                this.serviceProvider = serviceProvider;
            } else {
                Class<?> globalProxyCls = generateProviderProxyClass(globalProviderProxyHandler, serviceProvider.getClass());
                this.serviceProvider = copyProviderProperties(serviceProvider, newInstance(globalProxyCls));
            }
            return this;
        }

        @Override
        public ServiceWrapperWorker provider(ProviderProxyHandler proxyHandler, Object serviceProvider) {
            Class<?> proxyCls = generateProviderProxyClass(proxyHandler, serviceProvider.getClass());
            if (globalProviderProxyHandler == null) {
                this.serviceProvider = copyProviderProperties(serviceProvider, newInstance(proxyCls));
            } else {
                Class<?> globalProxyCls = generateProviderProxyClass(globalProviderProxyHandler, proxyCls);
                this.serviceProvider = copyProviderProperties(serviceProvider, newInstance(globalProxyCls));
            }
            return this;
        }

        @Override
        public List<ServiceWrapper> create() {

            List<ServiceWrapper> serviceWrappers = new ArrayList<ServiceWrapper>();

            //读取对象的方法注解
            RPCService rpcService;

            for (Class<?> cls = serviceProvider.getClass(); cls != Object.class; cls = cls.getSuperclass()) {
                Method[] methods = cls.getMethods();
                if (null != methods && methods.length > 0) {

                    for (Method method : methods) {
                        rpcService = method.getAnnotation(RPCService.class);
                        if (null != rpcService) {

                            //服务名
                            String serviceName = StringUtil.isNullOrEmpty(rpcService.serviceName()) ? method.getName() : rpcService.serviceName();
                            //负责人
                            String responsiblityName = rpcService.responsibilityName();
                            //方法weight
                            Integer weight = rpcService.weight();
                            //连接数 默认是1 一个实例一个1链接其实是够用的
                            Integer connCount = rpcService.connCount();
                            //是否支持服务降级
                            boolean isSupportDegradeService = rpcService.isSupportDegradeService();
                            //是否是VIP服务，如果是VIP服务，则默认是在port-2的端口暴露方法，与其他的方法使用不同的
                            boolean isVIPService = rpcService.isVIPService();
                            //暴露的降级方法的路径
                            String degradeServicePath = rpcService.degradeServicePath();
                            //降级方法的描述
                            String degradeServiceDesc = rpcService.degradeServiceDesc();
                            //是否进行限流
                            boolean isFlowControl = rpcService.isFlowController();
                            //每分钟调用的最大调用次数
                            Long maxCallCount = rpcService.maxCallCountInMinute();
                            if (maxCallCount <= 0) {
                                throw new RpcWrapperException("max call count must over zero at unit time");
                            }
                            ServiceFlowControllerManager serviceFlowControllerManager = providerController.getServiceFlowControllerManager();
                            // 设置服务单位时间最大限流量，且全局注册限流器 一个serviceName对应一个ServiceFlowController+
                            serviceFlowControllerManager.setServiceLimitVal(serviceName, maxCallCount);
                            //如果是支持服务降级服务，则需要根据降级方法的路径去创建这个实例，并编制proxy
                            if (isSupportDegradeService) {
                                Class<?> degradeClass = null;
                                try {
                                    degradeClass = Class.forName(degradeServicePath);
                                    Object nativeObj = degradeClass.newInstance();
                                    if (null == globalProviderProxyHandler) {
                                        this.mockDegradeServiceProvider = nativeObj;
                                    } else {
                                        Class<?> globalProxyCls = generateProviderProxyClass(globalProviderProxyHandler, nativeObj.getClass());
                                        this.mockDegradeServiceProvider = copyProviderProperties(nativeObj, newInstance(globalProxyCls));
                                    }
                                } catch (Exception e) {
                                    logger.error("[{}] class can not create by reflect [{}]", degradeServicePath, e.getMessage());
                                    throw new RpcWrapperException("degradeService path " + degradeServicePath + "create failed");
                                }

                            }

                            String methodName = method.getName();
                            Class<?>[] classes = method.getParameterTypes();
                            List<Class<?>[]> paramters = new ArrayList<>();
                            paramters.add(classes);

                            ServiceWrapper serviceWrapper = new ServiceWrapper(serviceProvider,
                                    mockDegradeServiceProvider,
                                    serviceName,
                                    responsiblityName,
                                    methodName,
                                    paramters,
                                    isSupportDegradeService,
                                    degradeServicePath,
                                    degradeServiceDesc,
                                    weight,
                                    connCount,
                                    isVIPService,
                                    isFlowControl,
                                    maxCallCount);
                            //放入到一个缓存中，方便以后consumer来调取服务的时候，该来获取对应真正的编织类
                            providerController.getProviderContainer().registerService(serviceName, serviceWrapper);

                            serviceWrappers.add(serviceWrapper);
                        }
                    }
                }
            }
            return serviceWrappers;
        }

        private <T> Class<? extends T> generateProviderProxyClass(ProviderProxyHandler proxyHandler, Class<T> providerCls) {

            try {
                return new ByteBuddy()
                        .subclass(providerCls)
                        .method(isDeclaredBy(providerCls))
                        .intercept(to(proxyHandler, "handler").filter(not(isDeclaredBy(Object.class))))
                        .make()
                        .load(providerCls.getClassLoader(), INJECTION)
                        .getLoaded();
            } catch (Exception e) {
                logger.error("Generate proxy [{}, handler: {}] fail: {}.", providerCls, proxyHandler, e.getMessage());
                return providerCls;
            }
        }

        private <F, T> T copyProviderProperties(F provider, T proxy) {
            List<String> providerFieldNames = new ArrayList<String>();

            for (Class<?> cls = provider.getClass(); cls != null; cls = cls.getSuperclass()) {
                try {
                    for (Field f : cls.getDeclaredFields()) {
                        providerFieldNames.add(f.getName());
                    }
                } catch (Throwable ignored) {
                }
            }

            for (String name : providerFieldNames) {
                try {
                    setValue(proxy, name, getValue(provider, name));
                } catch (Throwable ignored) {
                }
            }
            return proxy;
        }


    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (String s : list) {
            System.out.println(s);
        }
    }

}
